#! /usr/bin/env python

import sys
from optparse import OptionParser
import random
import math

from common.zerror import zassert
from common.zutils import convert


class SegmentationCore:
    def __init__(self, seed=0, addresses="-1", asize="1k", physmem="16k", numaddrs=5,
                 b0="-1", l0="-1", b1="-1", l1="-1", compute=False):
        parser = OptionParser()
        parser.add_option("-s", "--seed", default=seed, help="the random seed",
                          action="store", type="int", dest="seed")
        parser.add_option("-A", "--addresses", default=addresses,
                          help="a set of comma-separated pages to access; -1 means randomly generate",
                          action="store", type="string", dest="addresses")
        parser.add_option("-a", "--asize", default=asize,
                          help="address space size (e.g., 16, 64k, 32m, 1g)",
                          action="store", type="string", dest="asize")
        parser.add_option("-p", "--physmem", default=physmem,
                          help="physical memory size (e.g., 16, 64k, 32m, 1g)",
                          action="store", type="string", dest="psize")
        parser.add_option("-n", "--numaddrs", default=numaddrs,
                          help="number of virtual addresses to generate",
                          action="store", type="int", dest="num")
        parser.add_option("-b", "--b0", default=b0,
                          help="value of segment 0 base register",
                          action="store", type="string", dest="base0")
        parser.add_option("-l", "--l0", default=l0,
                          help="value of segment 0 limit register",
                          action="store", type="string", dest="len0")
        parser.add_option("-B", "--b1", default=b1,
                          help="value of segment 1 base register",
                          action="store", type="string", dest="base1")
        parser.add_option("-L", "--l1", default=l1,
                          help="value of segment 1 limit register",
                          action="store", type="string", dest="len1")
        parser.add_option("-c", help="compute answers for me",
                          action="store_true", default=compute, dest="solve")

        (self.options, self.args) = parser.parse_args()
        self.deal_args()

    def deal_args(self):
        options = self.options

        random.seed(options.seed)
        asize = convert(options.asize)
        psize = convert(options.psize)
        addresses = str(options.addresses)

        if psize <= 1:
            zassert('Error: must specify a non-zero physical memory size.')

        if asize == 0:
            zassert('Error: must specify a non-zero address-space size.')

        if psize <= asize:
            zassert('Error: physical memory size must be GREATER than address space size (for this simulation)')

        #
        # need to generate base, bounds for segment registers
        #
        len0 = convert(options.len0)
        len1 = convert(options.len1)
        base0 = convert(options.base0)
        base1 = convert(options.base1)

        if len0 == -1:
            len0 = int(asize / 4.0 + (asize / 4.0 * random.random()))

        if len1 == -1:
            len1 = int(asize / 4.0 + (asize / 4.0 * random.random()))

        # now have to find room for them
        if base0 == -1:
            done = 0
            while done == 0:
                base0 = int(psize * random.random())
                if (base0 + len0) < psize:
                    done = 1

        # internally, base1 points to the lower address, and base1+len1 the higher address
        # (this differs from what the user would pass in, for example)
        if base1 == -1:
            done = 0
            while done == 0:
                base1 = int(psize * random.random())
                if (base1 + len1) < psize:
                    if (base1 > (base0 + len0)) or ((base1 + len1) < base0):
                        done = 1
        else:
            base1 = base1 - len1

        if len0 > asize / 2.0 or len1 > asize / 2.0:
            zassert('Error: length register is too large for this address space')

        print('Segment register information:')
        print('')
        print('  Segment 0 base  (grows positive) : 0x%08x (decimal %d)' % (base0, base0))
        print('  Segment 0 limit                  : %d' % (len0))
        print('')
        print('  Segment 1 base  (grows negative) : 0x%08x (decimal %d)' % (base1 + len1, base1 + len1))
        print('  Segment 1 limit                  : %d' % (len1))
        print('')
        nbase1 = base1 + len1

        if (len0 + base0) > (base1) and (base1 > base0):
            zassert('Error: segments overlap in physical memory')

        addrList = []
        if addresses == '-1':
            # need to generate addresses
            for i in range(0, options.num):
                n = int(asize * random.random())
                addrList.append(n)
        else:
            addrList = addresses.split(',')

        #
        # now, need to generate virtual address trace
        #
        print('Virtual Address Trace')
        i = 0
        for vStr in addrList:
            # vaddr = int(asize * random.random())
            vaddr = int(vStr)
            if vaddr < 0 or vaddr >= asize:
                zassert('Error: virtual address %d cannot be generated in an address space of size %d' % (vaddr, asize))
            if options.solve is False:
                print('  VA %2d: 0x%08x (decimal: %4d) --> PA or segmentation violation?' % (i, vaddr, vaddr))
            else:
                paddr = 0
                if (vaddr >= (asize / 2)):
                    # seg 1
                    paddr = nbase1 + (vaddr - asize)
                    if paddr < base1:
                        print('  VA %2d: 0x%08x (decimal: %4d) --> SEGMENTATION VIOLATION (SEG1)' % (i, vaddr, vaddr))
                    else:
                        print('  VA %2d: 0x%08x (decimal: %4d) --> VALID in SEG1: 0x%08x (decimal: %4d)' % (
                            i, vaddr, vaddr, paddr, paddr))
                else:
                    # seg 0
                    if (vaddr >= len0):
                        print('  VA %2d: 0x%08x (decimal: %4d) --> SEGMENTATION VIOLATION (SEG0)' % (i, vaddr, vaddr))
                    else:
                        paddr = vaddr + base0
                        print('  VA %2d: 0x%08x (decimal: %4d) --> VALID in SEG0: 0x%08x (decimal: %4d)' % (
                            i, vaddr, vaddr, paddr, paddr))
            i += 1

        print('')

        if not options.solve:
            print('对于每一个虚拟地址，若合法则计算其对应的物理地址，若不合法则指明其为segmentation violation'
                  '在本问题中，你可以假设系统只有两个段，虚拟地址的最高位用于指定段号。需要注意的是两个段的生长'
                  '方向是相反的，段0从低地址向高地址生长。')


def main():
    core = SegmentationCore()


if __name__ == "__main__":
    main()
